package com.chester.springbootseventeen.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.security.*;
import java.security.cert.CertificateException;
import java.util.*;

/**
 * @author chester7cheng
 * @since 2018-10-23
 */
@Slf4j
public class HttpClientSslUtil {

    private static final String KEY_STORE_TYPE_P12 = "PKCS12";
    private static final String KEY_STORE_TYPE_JKS = "JKS";


    /**
     * //$ openssl pkcs12 -export -in dev.cert.pem -inkey dev.key.pem -out dev.cert.p12 -passout pass:123456
     * //$ keytool -importkeystore -srckeystore dev.cert.p12 -srcstoretype PKCS12 -srcstorepass 123456 -deststorepass 123456 -destkeystore dev.cert.jks
     */
    private static final String KEY_STORE_CLIENT_PATH = "cer/pinjam-keystore.jks";
    /**
     * $ keytool -import -noprompt -file ca-chain.pem -keystore ca-chain.jks -storepass 123456
     */
    private static final String KEY_STORE_SERVER_PATH = "cer/pinjam-truststore.jks";
    private static final String KEY_STORE_CLIENT_PASSWORD = "password";

    private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().setSocketTimeout(5000).setConnectTimeout(5000).setConnectionRequestTimeout(5000).build();

    public static void main(String[] args) throws Exception {
        getToken();
    }

    public static String getToken() {
        HttpUriRequest httpUriRequest = getTokenRequest();
        HttpClient httpClient = getSslHttpClient(true);

        return execute(httpClient, httpUriRequest);
    }

    /**
     * post请求 json参数
     *
     * @param url
     * @param jsonParams
     * @param headers
     * @return
     * @throws IOException
     */
    public static String doPostJSON(String url, JSONObject jsonParams, Map<String, String> headers) {
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Content-Type", "application/json");
        for (String key : headers.keySet()) {
            String value = headers.get(key);
            httpPost.setHeader(key, value);
        }

        try {
            httpPost.setEntity(new StringEntity(jsonParams.toString()));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        HttpClient httpClient = getSslHttpClient(true);

        return execute(httpClient, httpPost);
    }


    private static String execute(HttpClient httpClient, HttpUriRequest httpUriRequest){
        HttpResponse httpResponse = null;
        try {
            httpResponse = httpClient.execute(httpUriRequest);
        } catch (IOException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        }

        if (HttpStatus.SC_OK == (httpResponse != null ? httpResponse.getStatusLine().getStatusCode() : 0)) {
            HttpEntity entity = httpResponse.getEntity();
            String message = null;
            try {
                message = EntityUtils.toString(entity, "utf-8");
            } catch (IOException e) {
                e.getMessage();
                e.printStackTrace();
            }
            log.trace(message);
            return message;
        } else {
            log.error("请求失败：" + JSON.toJSONString(httpResponse));
            return null;
        }
    }

//    /**
//     * post k-v参数
//     *
//     * @param url
//     * @param params
//     * @param headers
//     * @return
//     * @throws IOException
//     */
//    public static String doPostMap(String url, Map<String, String> params, Map<String, String> headers)
//            throws IOException {
//        HttpPost httpPost = new HttpPost(url);
//        if (params != null && params.keySet().isEmpty()) {
//            List<NameValuePair> list = new ArrayList<>();
//
//            Set<String> keySet = headers.keySet();
//            Iterator<String> iterator = keySet.iterator();
//            while (iterator.hasNext()) {
//                String key = iterator.next();
//                String value = headers.get(key);
//                list.add(new BasicNameValuePair(key, value));
//            }
//            httpPost.setEntity(new UrlEncodedFormEntity(list));
//        }
//
//        if (headers != null && headers.keySet().isEmpty()) {
//            Set<String> keySet = headers.keySet();
//            Iterator<String> iterator = keySet.iterator();
//            while (iterator.hasNext()) {
//                String key = iterator.next();
//                String value = headers.get(key);
//                httpPost.addHeader(key, value);
//            }
//
//        }
//        return execute(httpPost);
//    }

//    /**
//     * get请求
//     *
//     * @param url
//     * @param params
//     * @param headers
//     * @return
//     * @throws IOException
//     */
//    public static String doGet(String url, Map<String, String> params, Map<String, String> headers) throws IOException {
//        // 参数
//        StringBuilder paramsBuilder = new StringBuilder(url);
//
//        String questionMark = "?";
//        if (params != null && params.keySet().isEmpty()) {
//            if (!url.contains(questionMark)) {
//                paramsBuilder.append(questionMark);
//            }
//            List<NameValuePair> list = new ArrayList<>();
//
//            Set<String> keySet = headers.keySet();
//            Iterator<String> iterator = keySet.iterator();
//            while (iterator.hasNext()) {
//                String key = iterator.next();
//                String value = headers.get(key);
//                list.add(new BasicNameValuePair(key, value));
//            }
//            String paramsStr = EntityUtils.toString(new UrlEncodedFormEntity(list));
//            paramsBuilder.append(paramsStr);
//        }
//        HttpGet httpGet = new HttpGet(paramsBuilder.toString());
//        // 头
//        if (headers != null && headers.keySet().isEmpty()) {
//            Set<String> keySet = headers.keySet();
//            Iterator<String> iterator = keySet.iterator();
//            while (iterator.hasNext()) {
//                String key = iterator.next();
//                String value = headers.get(key);
//                httpGet.addHeader(key, value);
//            }
//
//        }
//        return execute(httpGet);
//    }

//    /**
//     * 执行请求并返回string值
//     *
//     * @param httpUriRequest
//     * @return
//     * @throws IOException
//     */
//    private static String execute(HttpUriRequest httpUriRequest) {
//        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
//            CloseableHttpResponse response = httpClient.execute(httpUriRequest);
//            if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
//                try (BufferedReader bufferedReader = new BufferedReader(
//                        new InputStreamReader(response.getEntity().getContent()))) {
//                    String result = "";
//                    String tmp = null;
//                    while ((tmp = bufferedReader.readLine()) != null) {
//                        result += tmp;
//                    }
//                    return result;
//                }
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return null;
//    }

    private static KeyStore keyStore = null;
    private static KeyStore trustStore = null;
    private static synchronized HttpClient getSslHttpClient(boolean loadJks) {
        SSLContext sslContext = null;
        if (loadJks) {
            try {
                // 服务器端需要验证的客户端证书
                if(keyStore == null){
                    keyStore = loadKeyStore(KEY_STORE_CLIENT_PATH, KEY_STORE_CLIENT_PASSWORD, KEY_STORE_TYPE_JKS);
                }
                // 客户端信任的服务器端证书
                if(trustStore == null){
                    trustStore = loadKeyStore(KEY_STORE_SERVER_PATH, KEY_STORE_CLIENT_PASSWORD, KEY_STORE_TYPE_JKS);

                }
                sslContext = SSLContexts.custom()
                        .loadKeyMaterial(keyStore, KEY_STORE_CLIENT_PASSWORD.toCharArray())
                        .loadTrustMaterial(trustStore, new TrustSelfSignedStrategy())
                        .build();
            } catch (NoSuchAlgorithmException | UnrecoverableKeyException | KeyStoreException | KeyManagementException e) {
                log.error(e.getMessage());
                e.printStackTrace();
            }
        } else {
            try {
                sslContext = SSLContexts.custom().build();
            } catch (NoSuchAlgorithmException | KeyManagementException e) {
                e.printStackTrace();
            }
        }

        assert sslContext != null;
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
        return HttpClients.custom().setSSLSocketFactory(sslsf).build();

    }

    private static KeyStore loadKeyStore(String path, String password, String type) {
        KeyStore keyStore = null;
        InputStream inputStream = null;
        try {
            // 服务器端需要验证的客户端证书
            keyStore = KeyStore.getInstance(type);
            inputStream = new ClassPathResource(path).getInputStream();
            keyStore.load(inputStream, password.toCharArray());

        } catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException e) {
            log.error(e.getMessage());
            e.printStackTrace();
        } finally {
            try {
                assert inputStream != null;
                inputStream.close();
            } catch (IOException e) {
                log.error(e.getMessage());
                e.printStackTrace();
            }
        }

        return keyStore;
    }

    private static HttpUriRequest getTokenRequest() {
        RequestBuilder requestBuilder = RequestBuilder.post()
                .setConfig(REQUEST_CONFIG)
                .setUri("https://api.preprod.geerong.com:8443/oauth/token?grant_type=client_credentials")
                .addHeader("Content-Type", "application/x-www-form-urlencode")
                .addHeader("Authorization", "Basic MjRmZmQxNDItYWYzYS00ZDgyLThlYWItYWZiMGRiYzcyZjJjOnkzNEZseDNiaEJUUzVidTV4V3RKRFc1dWRiNWxvcXlvaUFBbjJGT3BVYkR0N1lrZk9tQkRkM1d0YVhLemxNNzk=");

        return requestBuilder.build();
    }
}
